<template>
  <div
    class="vk-form-item"
    :class="{
      'is-error': validateStatus.state === 'error',
      'is-success': validateStatus.state === 'success',
      'is-loading': validateStatus.loading,
      'is-required': isRequired
    }"
  >
  <!-- 分为两部分，左边的lable和右边的内容 -->
    <label class="vk-form-item__label">
      <!-- 作用域插槽，可以插入一些更复杂的结构 -->
      <slot name="label" :label="label">
        {{ label }}
      </slot>
    </label>
    <div class="vk-form-item__content">
      <slot :validate="validate" />
      <div v-if="validateStatus.state === 'error'" class="vk-form-item__error-msg">
        {{ validateStatus.errorMsg }}
      </div>
    </div>
    <!-- {{ innerValue }} - {{ itemRules }} -->
  </div>
</template>
<script setup lang="ts">
import { inject, computed, reactive, provide, onMounted, onUnmounted } from 'vue'
import { isNil } from 'lodash-es'
import Schema from 'async-validator'
import type {
  FormItemProps,
  FormValidateFailure,
  FormItemContext,
  ValidateStatusProp,
  FormItemInstance
} from './types'
import { formContextKey, formItemContextKey } from './types'
defineOptions({
  name: 'VKFormItem'
})
const props = defineProps<FormItemProps>()
// 子组件获取数据
const formContext = inject(formContextKey)

const validateStatus: ValidateStatusProp = reactive({
  state: 'init',
  errorMsg: '',
  loading: false
})
// 保存最初的值
let initialValue: any = null
// 拿到表单对应的值
const innerValue = computed(() => {
  const model = formContext?.model
  // isNil只判断null/undefined 
  if (model && props.prop && !isNil(model[props.prop])) {
    return model[props.prop]
  } else {
    return null
  }
})

// 拿到表单对应的校验规则
const itemRules = computed(() => {
  const rules = formContext?.rules
  if (rules && props.prop && rules[props.prop]) {
    return rules[props.prop]
  } else {
    return []
  }
})

// 清除，把响应式对象validateStatus清空
const clearValidate = () => {
  validateStatus.state = 'init'
  validateStatus.errorMsg = ''
  validateStatus.loading = false
}
// 恢复最初的值
const resetField = () => {
  clearValidate()
  const model = formContext?.model
  if (model && props.prop && !isNil(model[props.prop])) {
    model[props.prop] = initialValue
  }
}

const getTriggeredRules = (trigger?: string) => {
  const rules = itemRules.value
  if (rules) {
    return rules.filter((rule) => {
      // 如果没有传trigger则任何情况下都需要进行验证
      if (!trigger || !rule.trigger) return true
      // 当规则的trigger和我们传入的trigger相同时才进行验证
      return rule.trigger && rule.trigger === trigger
    })
  } else {
    return []
  }
}
// 用于必选项样式加*（rules中有一项是必选的就是必选项）
const isRequired = computed(() => {
  return itemRules.value.some((rule) => rule.required)
})
const validate = async (trigger?: string) => {
  // 用于拿到对应名字的规则例如name的规则
  const modelName = props.prop
  const triggeredRules = getTriggeredRules(trigger)
  if (!triggeredRules.length) return true
  if (modelName) {
    // 写规则
    const validator = new Schema({
      [modelName]: triggeredRules
    })
    validateStatus.loading = true
    // 写内容
    return validator.validate({ [modelName]: innerValue.value })
      .then(() => {
        validateStatus.state = 'success'
      })
      .catch((e: FormValidateFailure) => {
        const { errors } = e
        validateStatus.state = 'error'
        // validateStatus.errorMsg = errors && errors.length ? errors[0].message || '' : ''
        validateStatus.errorMsg = errors?.[0]?.message || ''
        // 错误信息被catch，但form中需要错误信息，再返回一下
        return Promise.reject(e)
      })
      .finally(() => {
        validateStatus.loading = false
      })
  }
}
// 把validate提供出去
const context: FormItemContext = {
  validate,
  prop: props.prop || '',
  clearValidate,
  resetField
}
provide(formItemContextKey, context)
onMounted(() => {
  if (props.prop) {
    formContext?.addField(context)
    // 得到最初值，用于清空后恢复初始值
    initialValue = innerValue.value
  }
})
onUnmounted(() => {
  formContext?.removeField(context)
})

defineExpose<FormItemInstance>({
  validateStatus,
  validate,
  resetField,
  clearValidate
})
</script>
